<template>
  <el-cascader
    :key="dataKey"
    v-model="chioseKey"
    :options="datas"
    :placeholder="placeholder"
    :props="props"
    :clearable="clearable"
    :disabled="disabled"
    class="el-input"
    @change="handleChange"
  />
</template>

<script>
import { GetStructures } from '@/customForm/api/form'
import { unref } from 'vue'
import { joinStr } from '@/utils'
export default {
  props: {
    clearable: {
      type: Boolean,
      default: true
    },
    placeholder: {
      type: String,
      default: '选择表单'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    filter: {
      type: Function,
      default: null
    },
    formId: {
      type: Array,
      default: null
    },
    funcType: {
      type: Array,
      default: null
    },
    filterDataType: {
      type: Array,
      default: null
    },
    showMode: {
      type: Array,
      default: null
    },
    isSysCol: {
      type: Boolean,
      default: false
    },
    limitTableId: {
      type: Array,
      default: null
    },
    isMulite: {
      type: Boolean,
      default: false
    },
    max: {
      // eslint-disable-next-line vue/require-prop-type-constructor
      type: Number | Function,
      default: null
    },
    ver: {
      type: Number,
      default: 0
    },
    modelValue: {
      default: null
    },
    source: {
      type: Object,
      default: null
    },
    labelField: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      datas: [],
      dataKey: null,
      id: 1,
      chioseKey: null,
      cache: {},
      table: {},
      isInit: false,
      oldVer: 0,
      dataSource: null,
      props: {
        multiple: false,
        emitPath: false,
        checkStrictly: true,
        value: 'Id',
        label: 'Label',
        children: 'Children'
      }
    }
  },
  computed: {},
  watch: {
    isMulite: {
      handler(val) {
        this.props.multiple = val
      },
      immediate: true
    },
    formId: {
      handler(val) {
        if (val && val.length > 0) {
          this.loadTree()
        }
      },
      immediate: true
    },
    ver: {
      handler(val) {
        if (
          (this.oldVer !== val || this.isInit === false) &&
          this.formId &&
          this.formId.length > 0
        ) {
          this.loadTree()
        }
      },
      immediate: true
    },
    modelValue: {
      handler(val) {
        if (this.chioseKey !== val && this.isInit) {
          this.chioseKey = val
          this.controlChange(val)
        }
      },
      immediate: true
    }
  },
  methods: {
    refreshLabel() {
      if (this.labelField == null || this.source == null) {
        return
      } else if (this.chioseKey == null || this.chioseKey.length === 0) {
        unref(this.source)[this.labelField] = null
      } else if (Array.isArray(this.chioseKey)) {
        unref(this.source)[this.labelField] = joinStr(this.chioseKey, (c) => this.cache[c].Label)
      } else {
        unref(this.source)[this.labelField] = this.cache[this.chioseKey].Label
      }
    },
    async loadTree() {
      const res = await GetStructures({
        FormId: this.formId,
        TableId: this.limitTableId,
        FuncType: this.funcType,
        DataType: this.filterDataType,
        ShowMode: this.showMode,
        IsSystem: this.isSysCol
      })
      res.forEach((c) => {
        this.format(c, c.Id, null)
      })
      this.dataSource = res
      this.refresh()
      if (this.modelValue != null && this.modelValue.length > 0) {
        this.chioseKey = this.modelValue
        this.controlChange(this.modelValue)
      } else {
        this.refreshLabel()
      }
      this.isInit = true
    },
    refresh() {
      this.dataKey = 'data_' + this.id
      this.id = this.id + 1
      let list
      if (this.filter != null) {
        list = this.filter(this.dataSource)
      } else {
        list = this.dataSource
      }
      if (list.length === 1) {
        this.datas = list[0].Children
      } else {
        this.datas = list
      }
    },
    format(row, formId, tableId) {
      this.cache[row.Id] = row
      if (row.Type !== 2) {
        row.disabled = true
      } else {
        row.FormId = formId
        row.TableId = tableId
      }
      if (row.Children != null && row.Children.length !== 0) {
        row.disabled = true
        if (row.Type === 0 || row.Type === 3 || row.Type === 5) {
          tableId = row.Id
          this.table[tableId] = row
        }
        row.Children.forEach((c) => {
          this.format(c, formId, tableId)
        })
      }
    },
    refreshRow(row, isDis) {
      if (row.Children != null && row.Children.length !== 0) {
        let isSet = false
        row.Children.forEach((c) => {
          if (this.refreshRow(c, isDis)) {
            isSet = true
          }
        })
        return isSet
      } else if (row.Type === 2) {
        if (this.chioseKey.includes(row.Id) === false) {
          if (row.disabled !== isDis) {
            row.disabled = isDis
            return true
          }
          return false
        } else if (row.disabled) {
          row.disabled = false
          return true
        }
        return false
      }
    },
    checkLimit() {
      if (this.isMulite === false || this.max == null) {
        return
      } else {
        const t = this.max instanceof Function ? this.max() : this.max
        const isDis = this.chioseKey.length >= t
        let isSet = false
        this.datas.forEach((c) => {
          if (this.refreshRow(c, isDis)) {
            isSet = true
          }
        })
        if (isSet) {
          this.datas = this.datas.slice()
        }
      }
    },
    controlChange(val) {
      this.checkLimit()
      let e = {
        table: this.table,
        col: null,
        key: val
      }
      if (val !== null) {
        if (this.isMulite) {
          e.col = val.map((c) => this.cache[c])
        } else {
          e.col = this.cache[val]
        }
      }
      this.refreshLabel()
      this.$emit('update:modelValue', val)
      this.$emit('change', val, e)
    },
    handleChange(val) {
      this.controlChange(val)
    }
  }
}
</script>
